home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / cvs-1.8 / cvs-1 / cvs-1.8.1 / src / update.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  46.3 KB  |  1,831 lines

  1. /*
  2.  * Copyright (c) 1992, Brian Berliner and Jeff Polk
  3.  * Copyright (c) 1989-1992, Brian Berliner
  4.  * 
  5.  * You may distribute under the terms of the GNU General Public License as
  6.  * specified in the README file that comes with the CVS 1.4 kit.
  7.  * 
  8.  * "update" updates the version in the present directory with respect to the RCS
  9.  * repository.  The present version must have been created by "checkout". The
  10.  * user can keep up-to-date by calling "update" whenever he feels like it.
  11.  * 
  12.  * The present version can be committed by "commit", but this keeps the version
  13.  * in tact.
  14.  * 
  15.  * Arguments following the options are taken to be file names to be updated,
  16.  * rather than updating the entire directory.
  17.  * 
  18.  * Modified or non-existent RCS files are checked out and reported as U
  19.  * <user_file>
  20.  * 
  21.  * Modified user files are reported as M <user_file>.  If both the RCS file and
  22.  * the user file have been modified, the user file is replaced by the result
  23.  * of rcsmerge, and a backup file is written for the user in .#file.version.
  24.  * If this throws up irreconcilable differences, the file is reported as C
  25.  * <user_file>, and as M <user_file> otherwise.
  26.  * 
  27.  * Files added but not yet committed are reported as A <user_file>. Files
  28.  * removed but not yet committed are reported as R <user_file>.
  29.  * 
  30.  * If the current directory contains subdirectories that hold concurrent
  31.  * versions, these are updated too.  If the -d option was specified, new
  32.  * directories added to the repository are automatically created and updated
  33.  * as well.
  34.  */
  35.  
  36. #include "cvs.h"
  37. #ifdef SERVER_SUPPORT
  38. #include "md5.h"
  39. #endif
  40. #include "watch.h"
  41. #include "fileattr.h"
  42. #include "edit.h"
  43.  
  44. static int checkout_file PROTO((char *file, char *repository, List *entries,
  45.               RCSNode *rcsnode, Vers_TS *vers_ts, char *update_dir));
  46. #ifdef SERVER_SUPPORT
  47. static int patch_file PROTO((char *file, char *repository, List *entries,
  48.                RCSNode*rcsnode, Vers_TS *vers_ts, char *update_dir,
  49.                int *docheckout, struct stat *file_info,
  50.                unsigned char *checksum));
  51. #endif
  52. static int isemptydir PROTO((char *dir));
  53. static int merge_file PROTO((char *file, char *repository, List *entries,
  54.                Vers_TS *vers, char *update_dir));
  55. static int scratch_file PROTO((char *file, char *repository, List * entries,
  56.              char *update_dir));
  57. static Dtype update_dirent_proc PROTO((char *dir, char *repository, char *update_dir));
  58. static int update_dirleave_proc PROTO((char *dir, int err, char *update_dir));
  59. static int update_fileproc PROTO ((struct file_info *));
  60. static int update_filesdone_proc PROTO((int err, char *repository,
  61.                     char *update_dir));
  62. static int write_letter PROTO((char *file, int letter, char *update_dir));
  63. #ifdef SERVER_SUPPORT
  64. static void join_file PROTO((char *file, RCSNode *rcsnode, Vers_TS *vers_ts,
  65.                char *update_dir, List *entries, char *repository));
  66. #else
  67. static void join_file PROTO((char *file, RCSNode *rcsnode, Vers_TS *vers_ts,
  68.                char *update_dir, List *entries));
  69. #endif
  70.  
  71. static char *options = NULL;
  72. static char *tag = NULL;
  73. static char *date = NULL;
  74. static char *join_rev1, *date_rev1;
  75. static char *join_rev2, *date_rev2;
  76. static int aflag = 0;
  77. static int force_tag_match = 1;
  78. static int update_build_dirs = 0;
  79. static int update_prune_dirs = 0;
  80. static int pipeout = 0;
  81. #ifdef SERVER_SUPPORT
  82. static int patches = 0;
  83. #endif
  84. static List *ignlist = (List *) NULL;
  85. static time_t last_register_time;
  86. static const char *const update_usage[] =
  87. {
  88.     "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n",
  89.     "    [-I ign] [-W spec] [files...]\n",
  90.     "\t-A\tReset any sticky tags/date/kopts.\n",
  91.     "\t-P\tPrune empty directories.\n",
  92.     "\t-d\tBuild directories, like checkout does.\n",
  93.     "\t-f\tForce a head revision match if tag/date not found.\n",
  94.     "\t-l\tLocal directory only, no recursion.\n",
  95.     "\t-R\tProcess directories recursively.\n",
  96.     "\t-p\tSend updates to standard output.\n",
  97.     "\t-k kopt\tUse RCS kopt -k option on checkout.\n",
  98.     "\t-r rev\tUpdate using specified revision/tag.\n",
  99.     "\t-D date\tSet date to update from.\n",
  100.     "\t-j rev\tMerge in changes made between current revision and rev.\n",
  101.     "\t-I ign\tMore files to ignore (! to reset).\n",
  102.     "\t-W spec\tWrappers specification line.\n",
  103.     NULL
  104. };
  105.  
  106. /*
  107.  * update is the argv,argc based front end for arg parsing
  108.  */
  109. int
  110. update (argc, argv)
  111.     int argc;
  112.     char **argv;
  113. {
  114.     int c, err;
  115.     int local = 0;            /* recursive by default */
  116.     int which;                /* where to look for files and dirs */
  117.  
  118.     if (argc == -1)
  119.     usage (update_usage);
  120.  
  121.     ign_setup ();
  122.     wrap_setup ();
  123.  
  124.     /* parse the args */
  125.     optind = 1;
  126.     while ((c = getopt (argc, argv, "ApPflRQqduk:r:D:j:I:W:")) != -1)
  127.     {
  128.     switch (c)
  129.     {
  130.         case 'A':
  131.         aflag = 1;
  132.         break;
  133.         case 'I':
  134.         ign_add (optarg, 0);
  135.         break;
  136.         case 'W':
  137.         wrap_add (optarg, 0);
  138.         break;
  139.         case 'k':
  140.         if (options)
  141.             free (options);
  142.         options = RCS_check_kflag (optarg);
  143.         break;
  144.         case 'l':
  145.         local = 1;
  146.         break;
  147.         case 'R':
  148.         local = 0;
  149.         break;
  150.         case 'Q':
  151.         case 'q':
  152. #ifdef SERVER_SUPPORT
  153.         /* The CVS 1.5 client sends these options (in addition to
  154.            Global_option requests), so we must ignore them.  */
  155.         if (!server_active)
  156. #endif
  157.             error (1, 0,
  158.                "-q or -Q must be specified before \"%s\"",
  159.                command_name);
  160.         break;
  161.         case 'd':
  162.         update_build_dirs = 1;
  163.         break;
  164.         case 'f':
  165.         force_tag_match = 0;
  166.         break;
  167.         case 'r':
  168.         tag = optarg;
  169.         break;
  170.         case 'D':
  171.         date = Make_Date (optarg);
  172.         break;
  173.         case 'P':
  174.         update_prune_dirs = 1;
  175.         break;
  176.         case 'p':
  177.         pipeout = 1;
  178.         noexec = 1;        /* so no locks will be created */
  179.         break;
  180.         case 'j':
  181.         if (join_rev2)
  182.             error (1, 0, "only two -j options can be specified");
  183.         if (join_rev1)
  184.             join_rev2 = optarg;
  185.         else
  186.             join_rev1 = optarg;
  187.         break;
  188.         case 'u':
  189. #ifdef SERVER_SUPPORT
  190.         if (server_active)
  191.             patches = 1;
  192.         else
  193. #endif
  194.             usage (update_usage);
  195.         break;
  196.         case '?':
  197.         default:
  198.         usage (update_usage);
  199.         break;
  200.     }
  201.     }
  202.     argc -= optind;
  203.     argv += optind;
  204.  
  205. #ifdef CLIENT_SUPPORT
  206.     if (client_active) 
  207.     {
  208.     /* The first pass does the regular update.  If we receive at least
  209.        one patch which failed, we do a second pass and just fetch
  210.        those files whose patches failed.  */
  211.     do
  212.     {
  213.         int status;
  214.  
  215.         start_server ();
  216.  
  217.         if (local)
  218.         send_arg("-l");
  219.         if (update_build_dirs)
  220.         send_arg("-d");
  221.         if (pipeout)
  222.         send_arg("-p");
  223.         if (!force_tag_match)
  224.         send_arg("-f");
  225.         if (aflag)
  226.         send_arg("-A");
  227.         if (update_prune_dirs)
  228.         send_arg("-P");
  229.         client_prune_dirs = update_prune_dirs;
  230.         option_with_arg ("-r", tag);
  231.         if (date)
  232.         client_senddate (date);
  233.         if (join_rev1)
  234.         option_with_arg ("-j", join_rev1);
  235.         if (join_rev2)
  236.         option_with_arg ("-j", join_rev2);
  237.  
  238.         /* If the server supports the command "update-patches", that means
  239.            that it knows how to handle the -u argument to update, which
  240.            means to send patches instead of complete files.  */
  241.         if (failed_patches == NULL)
  242.         {
  243.         struct request *rq;
  244.  
  245.         for (rq = requests; rq->name != NULL; rq++)
  246.         {
  247.             if (strcmp (rq->name, "update-patches") == 0)
  248.             {
  249.             if (rq->status == rq_supported)
  250.             {
  251.                 send_arg("-u");
  252.             }
  253.             break;
  254.             }
  255.         }
  256.         }
  257.  
  258.         if (failed_patches == NULL)
  259.         {
  260.         send_file_names (argc, argv, SEND_EXPAND_WILD);
  261.         send_files (argc, argv, local, aflag);
  262.         }
  263.         else
  264.         {
  265.         int i;
  266.  
  267.         (void) printf ("%s client: refetching unpatchable files\n",
  268.                    program_name);
  269.  
  270.         if (toplevel_wd[0] != '\0'
  271.             && chdir (toplevel_wd) < 0)
  272.         {
  273.             error (1, errno, "could not chdir to %s", toplevel_wd);
  274.         }
  275.  
  276.         for (i = 0; i < failed_patches_count; i++)
  277.             (void) unlink_file (failed_patches[i]);
  278.         send_file_names (failed_patches_count, failed_patches, 0);
  279.         send_files (failed_patches_count, failed_patches, local,
  280.                 aflag);
  281.         }
  282.  
  283.         failed_patches = NULL;
  284.         failed_patches_count = 0;
  285.  
  286.         send_to_server ("update\012", 0);
  287.  
  288.         status = get_responses_and_close ();
  289.         if (status != 0)
  290.         return status;
  291.  
  292.     } while (failed_patches != NULL);
  293.  
  294.     return 0;
  295.     }
  296. #endif
  297.  
  298.     if (tag != NULL)
  299.     tag_check_valid (tag, argc, argv, local, aflag, "");
  300.     /* FIXME: We don't call tag_check_valid on join_rev1 and join_rev2
  301.        yet (make sure to handle ':' correctly if we do, though).  */
  302.  
  303.     /*
  304.      * If we are updating the entire directory (for real) and building dirs
  305.      * as we go, we make sure there is no static entries file and write the
  306.      * tag file as appropriate
  307.      */
  308.     if (argc <= 0 && !pipeout)
  309.     {
  310.     if (update_build_dirs)
  311.     {
  312.         if (unlink_file (CVSADM_ENTSTAT) < 0 && ! existence_error (errno))
  313.         error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT);
  314. #ifdef SERVER_SUPPORT
  315.         if (server_active)
  316.         server_clear_entstat (".", Name_Repository (NULL, NULL));
  317. #endif
  318.     }
  319.  
  320.     /* keep the CVS/Tag file current with the specified arguments */
  321.     if (aflag || tag || date)
  322.     {
  323.         WriteTag ((char *) NULL, tag, date);
  324. #ifdef SERVER_SUPPORT
  325.         if (server_active)
  326.         server_set_sticky (".", Name_Repository (NULL, NULL), tag, date);
  327. #endif
  328.     }
  329.     }
  330.  
  331.     /* look for files/dirs locally and in the repository */
  332.     which = W_LOCAL | W_REPOS;
  333.  
  334.     /* look in the attic too if a tag or date is specified */
  335.     if (tag != NULL || date != NULL || joining())
  336.     which |= W_ATTIC;
  337.  
  338.     /* call the command line interface */
  339.     err = do_update (argc, argv, options, tag, date, force_tag_match,
  340.              local, update_build_dirs, aflag, update_prune_dirs,
  341.              pipeout, which, join_rev1, join_rev2, (char *) NULL);
  342.  
  343.     /* free the space Make_Date allocated if necessary */
  344.     if (date != NULL)
  345.     free (date);
  346.  
  347.     return (err);
  348. }
  349.  
  350. /*
  351.  * Command line interface to update (used by checkout)
  352.  */
  353. int
  354. do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag,
  355.        xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir)
  356.     int argc;
  357.     char **argv;
  358.     char *xoptions;
  359.     char *xtag;
  360.     char *xdate;
  361.     int xforce;
  362.     int local;
  363.     int xbuild;
  364.     int xaflag;
  365.     int xprune;
  366.     int xpipeout;
  367.     int which;
  368.     char *xjoin_rev1;
  369.     char *xjoin_rev2;
  370.     char *preload_update_dir;
  371. {
  372.     int err = 0;
  373.     char *cp;
  374.  
  375.     /* fill in the statics */
  376.     options = xoptions;
  377.     tag = xtag;
  378.     date = xdate;
  379.     force_tag_match = xforce;
  380.     update_build_dirs = xbuild;
  381.     aflag = xaflag;
  382.     update_prune_dirs = xprune;
  383.     pipeout = xpipeout;
  384.  
  385.     /* setup the join support */
  386.     join_rev1 = xjoin_rev1;
  387.     join_rev2 = xjoin_rev2;
  388.     if (join_rev1 && (cp = strchr (join_rev1, ':')) != NULL)
  389.     {
  390.     *cp++ = '\0';
  391.     date_rev1 = Make_Date (cp);
  392.     }
  393.     else
  394.     date_rev1 = (char *) NULL;
  395.     if (join_rev2 && (cp = strchr (join_rev2, ':')) != NULL)
  396.     {
  397.     *cp++ = '\0';
  398.     date_rev2 = Make_Date (cp);
  399.     }
  400.     else
  401.     date_rev2 = (char *) NULL;
  402.  
  403.     /* call the recursion processor */
  404.     err = start_recursion (update_fileproc, update_filesdone_proc,
  405.                update_dirent_proc, update_dirleave_proc,
  406.                argc, argv, local, which, aflag, 1,
  407.                preload_update_dir, 1, 0);
  408.  
  409.     /* see if we need to sleep before returning */
  410.     if (last_register_time)
  411.     {
  412.     time_t now;
  413.  
  414.     (void) time (&now);
  415.     if (now == last_register_time)
  416.         sleep (1);            /* to avoid time-stamp races */
  417.     }
  418.  
  419.     return (err);
  420. }
  421.  
  422. /*
  423.  * This is the callback proc for update.  It is called for each file in each
  424.  * directory by the recursion code.  The current directory is the local
  425.  * instantiation.  file is the file name we are to operate on. update_dir is
  426.  * set to the path relative to where we started (for pretty printing).
  427.  * repository is the repository. entries and srcfiles are the pre-parsed
  428.  * entries and source control files.
  429.  * 
  430.  * This routine decides what needs to be done for each file and does the
  431.  * appropriate magic for checkout
  432.  */
  433. static int
  434. update_fileproc (finfo)
  435.     struct file_info *finfo;
  436. {
  437.     int retval;
  438.     Ctype status;
  439.     Vers_TS *vers;
  440.  
  441.     status = Classify_File (finfo->file, tag, date, options, force_tag_match,
  442.                 aflag, finfo->repository, finfo->entries, finfo->rcs, &vers,
  443.                 finfo->update_dir, pipeout);
  444.     if (pipeout)
  445.     {
  446.     /*
  447.      * We just return success without doing anything if any of the really
  448.      * funky cases occur
  449.      * 
  450.      * If there is still a valid RCS file, do a regular checkout type
  451.      * operation
  452.      */
  453.     switch (status)
  454.     {
  455.         case T_UNKNOWN:        /* unknown file was explicitly asked
  456.                      * about */
  457.         case T_REMOVE_ENTRY:    /* needs to be un-registered */
  458.         case T_ADDED:        /* added but not committed */
  459.         retval = 0;
  460.         break;
  461.         case T_CONFLICT:        /* old punt-type errors */
  462.         retval = 1;
  463.         break;
  464.         case T_UPTODATE:        /* file was already up-to-date */
  465.         case T_NEEDS_MERGE:        /* needs merging */
  466.         case T_MODIFIED:        /* locally modified */
  467.         case T_REMOVED:        /* removed but not committed */
  468.         case T_CHECKOUT:        /* needs checkout */
  469. #ifdef SERVER_SUPPORT
  470.         case T_PATCH:        /* needs patch */
  471. #endif
  472.         retval = checkout_file (finfo->file, finfo->repository, finfo->entries, finfo->rcs,
  473.                     vers, finfo->update_dir);
  474.         break;
  475.  
  476.         default:            /* can't ever happen :-) */
  477.         error (0, 0,
  478.                "unknown file status %d for file %s", status, finfo->file);
  479.         retval = 0;
  480.         break;
  481.     }
  482.     }
  483.     else
  484.     {
  485.     switch (status)
  486.     {
  487.         case T_UNKNOWN:        /* unknown file was explicitly asked
  488.                      * about */
  489.         case T_UPTODATE:        /* file was already up-to-date */
  490.         retval = 0;
  491.         break;
  492.         case T_CONFLICT:        /* old punt-type errors */
  493.         retval = 1;
  494.         (void) write_letter (finfo->file, 'C', finfo->update_dir);
  495.         break;
  496.         case T_NEEDS_MERGE:        /* needs merging */
  497.         if (noexec)
  498.         {
  499.             retval = 1;
  500.             (void) write_letter (finfo->file, 'C', finfo->update_dir);
  501.         }
  502.         else
  503.         {
  504.             if (wrap_merge_is_copy (finfo->file))
  505.             /* Should we be warning the user that we are
  506.              * overwriting the user's copy of the file?  */
  507.             retval = checkout_file (finfo->file, finfo->repository, finfo->entries,
  508.                         finfo->rcs, vers, finfo->update_dir);
  509.             else
  510.             retval = merge_file (finfo->file, finfo->repository, finfo->entries,
  511.                          vers, finfo->update_dir);
  512.         }
  513.         break;
  514.         case T_MODIFIED:        /* locally modified */
  515.         retval = 0;
  516.         if (vers->ts_conflict)
  517.         {
  518.             char *filestamp;
  519.             int retcode;
  520.  
  521.             /*
  522.              * If the timestamp has changed and no conflict indicators
  523.              * are found, it isn't a 'C' any more.
  524.              */
  525. #ifdef SERVER_SUPPORT
  526.             if (server_active)
  527.             retcode = vers->ts_conflict[0] != '=';
  528.             else {
  529.             filestamp = time_stamp (finfo->file);
  530.             retcode = strcmp (vers->ts_conflict, filestamp);
  531.             free (filestamp);
  532.             }
  533. #else
  534.             filestamp = time_stamp (finfo->file);
  535.             retcode = strcmp (vers->ts_conflict, filestamp);
  536.             free (filestamp);
  537. #endif
  538.  
  539.             if (retcode)
  540.             {
  541.             /*
  542.              * If the timestamps differ, look for Conflict
  543.              * indicators to see if 'C' anyway.
  544.              */
  545.             run_setup ("%s", GREP);
  546.             run_arg (RCS_MERGE_PAT);
  547.             run_arg (finfo->file);
  548.             retcode = run_exec (RUN_TTY, DEVNULL,
  549.                         RUN_TTY,RUN_NORMAL);
  550.             if (retcode == -1)
  551.             {
  552.                 error (1, errno,
  553.                 "fork failed while examining conflict in `%s'",
  554.                        finfo->fullname);
  555.             }
  556.             }
  557.             if (!retcode)
  558.             {
  559.             (void) write_letter (finfo->file, 'C', finfo->update_dir);
  560.             retval = 1;
  561.             }
  562.             else
  563.             {
  564.             /* Reregister to clear conflict flag. */
  565.             Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_rcs,
  566.                   vers->options, vers->tag,
  567.                   vers->date, (char *)0);
  568.             }
  569.         }
  570.         if (!retval)
  571.             retval = write_letter (finfo->file, 'M', finfo->update_dir);
  572.         break;
  573. #ifdef SERVER_SUPPORT
  574.         case T_PATCH:        /* needs patch */
  575.         if (patches)
  576.         {
  577.             int docheckout;
  578.             struct stat file_info;
  579.             unsigned char checksum[16];
  580.  
  581.             retval = patch_file (finfo->file, finfo->repository, finfo->entries, finfo->rcs,
  582.                      vers, finfo->update_dir, &docheckout,
  583.                      &file_info, checksum);
  584.             if (! docheckout)
  585.             {
  586.                 if (server_active && retval == 0)
  587.                 server_updated (finfo->file, finfo->update_dir, finfo->repository,
  588.                         SERVER_PATCHED, &file_info,
  589.                         checksum);
  590.             break;
  591.             }
  592.         }
  593.         /* Fall through.  */
  594.         /* If we're not running as a server, just check the
  595.            file out.  It's simpler and faster than starting up
  596.            two new processes (diff and patch).  */
  597.         /* Fall through.  */
  598. #endif
  599.         case T_CHECKOUT:        /* needs checkout */
  600.         retval = checkout_file (finfo->file, finfo->repository, finfo->entries, finfo->rcs,
  601.                     vers, finfo->update_dir);
  602. #ifdef SERVER_SUPPORT
  603.         if (server_active && retval == 0)
  604.             server_updated (finfo->file, finfo->update_dir, finfo->repository,
  605.                     SERVER_UPDATED, (struct stat *) NULL,
  606.                     (unsigned char *) NULL);
  607. #endif
  608.         break;
  609.         case T_ADDED:        /* added but not committed */
  610.         retval = write_letter (finfo->file, 'A', finfo->update_dir);
  611.         break;
  612.         case T_REMOVED:        /* removed but not committed */
  613.         retval = write_letter (finfo->file, 'R', finfo->update_dir);
  614.         break;
  615.         case T_REMOVE_ENTRY:    /* needs to be un-registered */
  616.         retval = scratch_file (finfo->file, finfo->repository, finfo->entries, finfo->update_dir);
  617. #ifdef SERVER_SUPPORT
  618.         if (server_active && retval == 0)
  619.             server_updated (finfo->file, finfo->update_dir, finfo->repository,
  620.                     SERVER_UPDATED, (struct stat *) NULL,
  621.                     (unsigned char *) NULL);
  622. #endif
  623.         break;
  624.         default:            /* can't ever happen :-) */
  625.         error (0, 0,
  626.                "unknown file status %d for file %s", status, finfo->file);
  627.         retval = 0;
  628.         break;
  629.     }
  630.     }
  631.  
  632.     /* only try to join if things have gone well thus far */
  633.     if (retval == 0 && join_rev1)
  634. #ifdef SERVER_SUPPORT
  635.     join_file (finfo->file, finfo->rcs, vers, finfo->update_dir, finfo->entries, finfo->repository);
  636. #else
  637.     join_file (finfo->file, finfo->rcs, vers, finfo->update_dir, finfo->entries);
  638. #endif
  639.  
  640.     /* if this directory has an ignore list, add this file to it */
  641.     if (ignlist)
  642.     {
  643.     Node *p;
  644.  
  645.     p = getnode ();
  646.     p->type = FILES;
  647.     p->key = xstrdup (finfo->file);
  648.     if (addnode (ignlist, p) != 0)
  649.         freenode (p);
  650.     }
  651.  
  652.     freevers_ts (&vers);
  653.     return (retval);
  654. }
  655.  
  656. static void update_ignproc PROTO ((char *, char *));
  657.  
  658. static void
  659. update_ignproc (file, dir)
  660.     char *file;
  661.     char *dir;
  662. {
  663.     (void) write_letter (file, '?', dir);
  664. }
  665.  
  666. /* ARGSUSED */
  667. static int
  668. update_filesdone_proc (err, repository, update_dir)
  669.     int err;
  670.     char *repository;
  671.     char *update_dir;
  672. {
  673.     /* if this directory has an ignore list, process it then free it */
  674.     if (ignlist)
  675.     {
  676.     ignore_files (ignlist, update_dir, update_ignproc);
  677.     dellist (&ignlist);
  678.     }
  679.  
  680.     /* Clean up CVS admin dirs if we are export */
  681.     if (strcmp (command_name, "export") == 0)
  682.     {
  683.     /* I'm not sure the existence_error is actually possible (except
  684.        in cases where we really should print a message), but since
  685.        this code used to ignore all errors, I'll play it safe.  */
  686.     if (unlink_file_dir (CVSADM) < 0 && !existence_error (errno))
  687.         error (0, errno, "cannot remove %s directory", CVSADM);
  688.     }
  689. #ifdef SERVER_SUPPORT
  690.     else if (!server_active && !pipeout)
  691. #else
  692.     else if (!pipeout)
  693. #endif /* SERVER_SUPPORT */
  694.     {
  695.         /* If there is no CVS/Root file, add one */
  696.         if (!isfile (CVSADM_ROOT))
  697.         Create_Root( (char *) NULL, CVSroot );
  698.     }
  699.  
  700.     return (err);
  701. }
  702.  
  703. /*
  704.  * update_dirent_proc () is called back by the recursion processor before a
  705.  * sub-directory is processed for update.  In this case, update_dirent proc
  706.  * will probably create the directory unless -d isn't specified and this is a
  707.  * new directory.  A return code of 0 indicates the directory should be
  708.  * processed by the recursion code.  A return of non-zero indicates the
  709.  * recursion code should skip this directory.
  710.  */
  711. static Dtype
  712. update_dirent_proc (dir, repository, update_dir)
  713.     char *dir;
  714.     char *repository;
  715.     char *update_dir;
  716. {
  717.     if (ignore_directory (update_dir))
  718.       {
  719.     /* print the warm fuzzy message */
  720.     if (!quiet)
  721.       error (0, 0, "Ignoring %s", update_dir);
  722.         return R_SKIP_ALL;
  723.       }
  724.  
  725.     if (!isdir (dir))
  726.     {
  727.     /* if we aren't building dirs, blow it off */
  728.     if (!update_build_dirs)
  729.         return (R_SKIP_ALL);
  730.  
  731.     if (noexec)
  732.     {
  733.         /* ignore the missing dir if -n is specified */
  734.         error (0, 0, "New directory `%s' -- ignored", dir);
  735.         return (R_SKIP_ALL);
  736.     }
  737.     else
  738.     {
  739.         /* otherwise, create the dir and appropriate adm files */
  740.         make_directory (dir);
  741.         Create_Admin (dir, update_dir, repository, tag, date);
  742.     }
  743.     }
  744.     /* Do we need to check noexec here? */
  745.     else if (!pipeout)
  746.     {
  747.     char *cvsadmdir;
  748.  
  749.     /* The directory exists.  Check to see if it has a CVS
  750.        subdirectory.  */
  751.  
  752.     cvsadmdir = xmalloc (strlen (dir) + 80);
  753.     strcpy (cvsadmdir, dir);
  754.     strcat (cvsadmdir, "/");
  755.     strcat (cvsadmdir, CVSADM);
  756.  
  757.     if (!isdir (cvsadmdir))
  758.     {
  759.         /* We cannot successfully recurse into a directory without a CVS
  760.            subdirectory.  Generally we will have already printed
  761.            "? foo".  */
  762.         free (cvsadmdir);
  763.         return R_SKIP_ALL;
  764.     }
  765.     free (cvsadmdir);
  766.     }
  767.  
  768.     /*
  769.      * If we are building dirs and not going to stdout, we make sure there is
  770.      * no static entries file and write the tag file as appropriate
  771.      */
  772.     if (!pipeout)
  773.     {
  774.     if (update_build_dirs)
  775.     {
  776.         char tmp[PATH_MAX];
  777.  
  778.         (void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
  779.         if (unlink_file (tmp) < 0 && ! existence_error (errno))
  780.         error (1, errno, "cannot remove file %s", tmp);
  781. #ifdef SERVER_SUPPORT
  782.         if (server_active)
  783.         server_clear_entstat (update_dir, repository);
  784. #endif
  785.     }
  786.  
  787.     /* keep the CVS/Tag file current with the specified arguments */
  788.     if (aflag || tag || date)
  789.     {
  790.         WriteTag (dir, tag, date);
  791. #ifdef SERVER_SUPPORT
  792.         if (server_active)
  793.         server_set_sticky (update_dir, repository, tag, date);
  794. #endif
  795.     }
  796.  
  797.     /* initialize the ignore list for this directory */
  798.     ignlist = getlist ();
  799.     }
  800.  
  801.     /* print the warm fuzzy message */
  802.     if (!quiet)
  803.     error (0, 0, "Updating %s", update_dir);
  804.  
  805.     return (R_PROCESS);
  806. }
  807.  
  808. /*
  809.  * update_dirleave_proc () is called back by the recursion code upon leaving
  810.  * a directory.  It will prune empty directories if needed and will execute
  811.  * any appropriate update programs.
  812.  */
  813. /* ARGSUSED */
  814. static int
  815. update_dirleave_proc (dir, err, update_dir)
  816.     char *dir;
  817.     int err;
  818.     char *update_dir;
  819. {
  820.     FILE *fp;
  821.  
  822.     /* run the update_prog if there is one */
  823.     if (err == 0 && !pipeout && !noexec &&
  824.     (fp = fopen (CVSADM_UPROG, "r")) != NULL)
  825.     {
  826.     char *cp;
  827.     char *repository;
  828.     char line[MAXLINELEN];
  829.  
  830.     repository = Name_Repository ((char *) NULL, update_dir);
  831.     if (fgets (line, sizeof (line), fp) != NULL)
  832.     {
  833.         if ((cp = strrchr (line, '\n')) != NULL)
  834.         *cp = '\0';
  835.         run_setup ("%s %s", line, repository);
  836.         (void) printf ("%s %s: Executing '", program_name, command_name);
  837.         run_print (stdout);
  838.         (void) printf ("'\n");
  839.         (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
  840.     }
  841.     (void) fclose (fp);
  842.     free (repository);
  843.     }
  844.  
  845.     /* FIXME: chdir ("..") loses with symlinks.  */
  846.     /* Prune empty dirs on the way out - if necessary */
  847.     (void) chdir ("..");
  848.     if (update_prune_dirs && isemptydir (dir))
  849.     {
  850.     /* I'm not sure the existence_error is actually possible (except
  851.        in cases where we really should print a message), but since
  852.        this code used to ignore all errors, I'll play it safe.  */
  853.     if (unlink_file_dir (dir) < 0 && !existence_error (errno))
  854.         error (0, errno, "cannot remove %s directory", dir);
  855.     }
  856.  
  857.     return (err);
  858. }
  859.  
  860. /*
  861.  * Returns 1 if the argument directory is completely empty, other than the
  862.  * existence of the CVS directory entry.  Zero otherwise.
  863.  */
  864. static int
  865. isemptydir (dir)
  866.     char *dir;
  867. {
  868.     DIR *dirp;
  869.     struct dirent *dp;
  870.  
  871.     if ((dirp = opendir (dir)) == NULL)
  872.     {
  873.     error (0, 0, "cannot open directory %s for empty check", dir);
  874.     return (0);
  875.     }
  876.     while ((dp = readdir (dirp)) != NULL)
  877.     {
  878.     if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0 &&
  879.         strcmp (dp->d_name, CVSADM) != 0)
  880.     {
  881.         (void) closedir (dirp);
  882.         return (0);
  883.     }
  884.     }
  885.     (void) closedir (dirp);
  886.     return (1);
  887. }
  888.  
  889. /*
  890.  * scratch the Entries file entry associated with a file
  891.  */
  892. static int
  893. scratch_file (file, repository, entries, update_dir)
  894.     char *file;
  895.     char *repository;
  896.     List *entries;
  897.     char *update_dir;
  898. {
  899.     history_write ('W', update_dir, "", file, repository);
  900.     Scratch_Entry (entries, file);
  901.     (void) unlink_file (file);
  902.     return (0);
  903. }
  904.  
  905. /*
  906.  * check out a file - essentially returns the result of the fork on "co".
  907.  */
  908. static int
  909. checkout_file (file, repository, entries, rcsnode, vers_ts, update_dir)
  910.     char *file;
  911.     char *repository;
  912.     List *entries;
  913.     RCSNode *rcsnode;
  914.     Vers_TS *vers_ts;
  915.     char *update_dir;
  916. {
  917.     char backup[PATH_MAX];
  918.     int set_time, retval = 0;
  919.     int retcode = 0;
  920.     int status;
  921.     int file_is_dead;
  922.  
  923.     /* don't screw with backup files if we're going to stdout */
  924.     if (!pipeout)
  925.     {
  926.     (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, file);
  927.     if (isfile (file))
  928.         rename_file (file, backup);
  929.     else
  930.         (void) unlink_file (backup);
  931.     }
  932.  
  933.     file_is_dead = RCS_isdead (vers_ts->srcfile, vers_ts->vn_rcs);
  934.  
  935.     if (!file_is_dead)
  936.     {
  937.     /*
  938.      * if we are checking out to stdout, print a nice message to
  939.      * stderr, and add the -p flag to the command */
  940.     if (pipeout)
  941.     {
  942.         if (!quiet)
  943.         {
  944.         (void) fprintf (stderr, "\
  945. ===================================================================\n");
  946.         if (update_dir[0])
  947.             (void) fprintf (stderr, "Checking out %s/%s\n",
  948.                     update_dir, file);
  949.         else
  950.             (void) fprintf (stderr, "Checking out %s\n", file);
  951.         (void) fprintf (stderr, "RCS:  %s\n", vers_ts->srcfile->path);
  952.         (void) fprintf (stderr, "VERS: %s\n", vers_ts->vn_rcs);
  953.         (void) fprintf (stderr, "***************\n");
  954.         }
  955.     }
  956.  
  957.     status = RCS_checkout (vers_ts->srcfile->path,
  958.                    pipeout ? NULL : file, vers_ts->vn_tag,
  959.                    vers_ts->options, RUN_TTY, 0, 0);
  960.     }
  961.     if (file_is_dead || status == 0)
  962.     {
  963.     if (!pipeout)
  964.     {
  965.         Vers_TS *xvers_ts;
  966.         int resurrecting;
  967.  
  968.         resurrecting = 0;
  969.  
  970.         if (file_is_dead && joining())
  971.         {
  972.         if (RCS_getversion (vers_ts->srcfile, join_rev1,
  973.                     date_rev1, 1, 0)
  974.             || (join_rev2 != NULL && 
  975.             RCS_getversion (vers_ts->srcfile, join_rev2,
  976.                     date_rev2, 1, 0)))
  977.         {
  978.             /* when joining, we need to get dead files checked
  979.                out.  Try harder.  */
  980.             /* I think that RCS_FLAGS_FORCE is here only because
  981.                passing -f to co used to enable checking out
  982.                a dead revision in the old version of death
  983.                support which used a hacked RCS instead of using
  984.                the RCS state.  */
  985.             retcode = RCS_checkout (vers_ts->srcfile->path, file,
  986.                                     vers_ts->vn_rcs,
  987.                                     vers_ts->options, RUN_TTY,
  988.                                     RCS_FLAGS_FORCE, 0);
  989.             if (retcode != 0)
  990.             {
  991.             error (retcode == -1 ? 1 : 0,
  992.                    retcode == -1 ? errno : 0,
  993.                    "could not check out %s", file);
  994.             (void) unlink_file (backup);
  995.             return (retcode);
  996.             }
  997.             file_is_dead = 0;
  998.             resurrecting = 1;
  999.         }
  1000.         else
  1001.         {
  1002.             /* If the file is dead and does not contain either of
  1003.                the join revisions, then we don't want to check it
  1004.                out. */
  1005.             return 0;
  1006.         }
  1007.         }
  1008.  
  1009.         if (cvswrite == TRUE
  1010.         && !file_is_dead
  1011.         && !fileattr_get (file, "_watched"))
  1012.         xchmod (file, 1);
  1013.  
  1014.         {
  1015.         /* A newly checked out file is never under the spell
  1016.            of "cvs edit".  If we think we were editing it
  1017.            from a previous life, clean up.  Would be better to
  1018.            check for same the working directory instead of
  1019.            same user, but that is hairy.  */
  1020.  
  1021.         struct addremove_args args;
  1022.  
  1023.         editor_set (file, getcaller (), NULL);
  1024.  
  1025.         memset (&args, 0, sizeof args);
  1026.         args.remove_temp = 1;
  1027.         watch_modify_watchers (file, &args);
  1028.         }
  1029.  
  1030.         /* set the time from the RCS file iff it was unknown before */
  1031.         if (vers_ts->vn_user == NULL ||
  1032.         strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
  1033.         {
  1034.         set_time = 1;
  1035.         }
  1036.         else
  1037.         set_time = 0;
  1038.  
  1039.         wrap_fromcvs_process_file (file);
  1040.  
  1041.         xvers_ts = Version_TS (repository, options, tag, date, file,
  1042.                   force_tag_match, set_time, entries, rcsnode);
  1043.         if (strcmp (xvers_ts->options, "-V4") == 0)
  1044.         xvers_ts->options[0] = '\0';
  1045.  
  1046.         (void) time (&last_register_time);
  1047.  
  1048.         if (file_is_dead)
  1049.         {
  1050.         if (xvers_ts->vn_user != NULL)
  1051.         {
  1052.             if (update_dir[0] == '\0')
  1053.             error (0, 0,
  1054.                    "warning: %s is not (any longer) pertinent",
  1055.                    file);
  1056.             else
  1057.             error (0, 0,
  1058.                    "warning: %s/%s is not (any longer) pertinent",
  1059.                    update_dir, file);
  1060.         }
  1061.         Scratch_Entry (entries, file);
  1062.         if (unlink_file (file) < 0 && ! existence_error (errno))
  1063.         {
  1064.             if (update_dir[0] == '\0')
  1065.             error (0, errno, "cannot remove %s", file);
  1066.             else
  1067.             error (0, errno, "cannot remove %s/%s", update_dir,
  1068.                    file);
  1069.         }
  1070.         }
  1071.         else
  1072.           Register (entries, file,
  1073.             resurrecting ? "0" : xvers_ts->vn_rcs,
  1074.             xvers_ts->ts_user, xvers_ts->options,
  1075.             xvers_ts->tag, xvers_ts->date,
  1076.             (char *)0); /* Clear conflict flag on fresh checkout */
  1077.  
  1078.         /* fix up the vers structure, in case it is used by join */
  1079.         if (join_rev1)
  1080.         {
  1081.         if (vers_ts->vn_user != NULL)
  1082.             free (vers_ts->vn_user);
  1083.         if (vers_ts->vn_rcs != NULL)
  1084.             free (vers_ts->vn_rcs);
  1085.         vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
  1086.         vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
  1087.         }
  1088.  
  1089.         /* If this is really Update and not Checkout, recode history */
  1090.         if (strcmp (command_name, "update") == 0)
  1091.         history_write ('U', update_dir, xvers_ts->vn_rcs, file,
  1092.                    repository);
  1093.  
  1094.         freevers_ts (&xvers_ts);
  1095.  
  1096.         if (!really_quiet && !file_is_dead)
  1097.         {
  1098.         write_letter (file, 'U', update_dir);
  1099.         }
  1100.     }
  1101.     }
  1102.     else
  1103.     {
  1104.     int old_errno = errno;        /* save errno value over the rename */
  1105.  
  1106.     if (!pipeout && isfile (backup))
  1107.         rename_file (backup, file);
  1108.  
  1109.     error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
  1110.            "could not check out %s", file);
  1111.  
  1112.     retval = retcode;
  1113.     }
  1114.  
  1115.     if (!pipeout)
  1116.     (void) unlink_file (backup);
  1117.  
  1118.     return (retval);
  1119. }
  1120.  
  1121. #ifdef SERVER_SUPPORT
  1122. /* Patch a file.  Runs rcsdiff.  This is only done when running as the
  1123.  * server.  The hope is that the diff will be smaller than the file
  1124.  * itself.
  1125.  */
  1126. static int
  1127. patch_file (file, repository, entries, rcsnode, vers_ts, update_dir,
  1128.         docheckout, file_info, checksum)
  1129.     char *file;
  1130.     char *repository;
  1131.     List *entries;
  1132.     RCSNode *rcsnode;
  1133.     Vers_TS *vers_ts;
  1134.     char *update_dir;
  1135.     int *docheckout;
  1136.     struct stat *file_info;
  1137.     unsigned char *checksum;
  1138. {
  1139.     char backup[PATH_MAX];
  1140.     char file1[PATH_MAX];
  1141.     char file2[PATH_MAX];
  1142.     int retval = 0;
  1143.     int retcode = 0;
  1144.     int fail;
  1145.     FILE *e;
  1146.  
  1147.     *docheckout = 0;
  1148.  
  1149.     if (pipeout || joining ())
  1150.     {
  1151.     *docheckout = 1;
  1152.     return 0;
  1153.     }
  1154.  
  1155.     (void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, file);
  1156.     if (isfile (file))
  1157.         rename_file (file, backup);
  1158.     else
  1159.         (void) unlink_file (backup);
  1160.     
  1161.     (void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, file);
  1162.     (void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, file);
  1163.  
  1164.     fail = 0;
  1165.  
  1166.     /* We need to check out both revisions first, to see if either one
  1167.        has a trailing newline.  Because of this, we don't use rcsdiff,
  1168.        but just use diff.  */
  1169.     if (noexec)
  1170.     retcode = 0;
  1171.     else
  1172.     retcode = RCS_checkout (vers_ts->srcfile->path, NULL,
  1173.                             vers_ts->vn_user,
  1174.                             vers_ts->options, file1, 0, 0);
  1175.     if (retcode != 0)
  1176.         fail = 1;
  1177.     else
  1178.     {
  1179.         e = fopen (file1, "r");
  1180.     if (e == NULL)
  1181.         fail = 1;
  1182.     else
  1183.     {
  1184.         if (fseek (e, (long) -1, SEEK_END) == 0
  1185.         && getc (e) != '\n')
  1186.         {
  1187.             fail = 1;
  1188.         }
  1189.         fclose (e);
  1190.     }
  1191.     }
  1192.  
  1193.     if (! fail)
  1194.     {
  1195.         /* Check it out into file, and then move to file2, so that we
  1196.            can get the right modes into *FILE_INFO.  We can't check it
  1197.            out directly into file2 because co doesn't understand how
  1198.            to do that.  */
  1199.     retcode = RCS_checkout (vers_ts->srcfile->path, file,
  1200.                             vers_ts->vn_rcs,
  1201.                             vers_ts->options, RUN_TTY, 0, 0);
  1202.     if (retcode != 0)
  1203.         fail = 1;
  1204.     else
  1205.     {
  1206.         if (!isreadable (file))
  1207.         {
  1208.             /* File is dead.  */
  1209.             fail = 1;
  1210.         }
  1211.         else
  1212.         {
  1213.             rename_file (file, file2);
  1214.         if (cvswrite == TRUE
  1215.             && !fileattr_get (file, "_watched"))
  1216.             xchmod (file2, 1);
  1217.         e = fopen (file2, "r");
  1218.         if (e == NULL)
  1219.             fail = 1;
  1220.         else
  1221.         {
  1222.             struct MD5Context context;
  1223.             int nl;
  1224.             unsigned char buf[8192];
  1225.             unsigned len;
  1226.  
  1227.             nl = 0;
  1228.  
  1229.             /* Compute the MD5 checksum and make sure there is
  1230.                        a trailing newline.  */
  1231.             MD5Init (&context);
  1232.             while ((len = fread (buf, 1, sizeof buf, e)) != 0)
  1233.             {
  1234.             nl = buf[len - 1] == '\n';
  1235.                 MD5Update (&context, buf, len);
  1236.             }
  1237.             MD5Final (checksum, &context);
  1238.  
  1239.             if (ferror (e) || ! nl)
  1240.             {
  1241.                 fail = 1;
  1242.             }
  1243.  
  1244.             fclose (e);
  1245.         }
  1246.         }
  1247.     }
  1248.     }      
  1249.  
  1250.     retcode = 0;
  1251.     if (! fail)
  1252.     {
  1253.     /* FIXME: This whole thing with diff/patch is rather more
  1254.        convoluted than necessary (lots of forks and execs, need to
  1255.        worry about versions of diff and patch, etc.).  Also, we
  1256.        send context lines which aren't needed (in the rare case in
  1257.        which the diff doesn't apply, the checksum would catches it).
  1258.        Solution perhaps is to librarify the RCS routines which apply
  1259.        deltas or something equivalent.  */
  1260.     /* This is -c, not -u, because we have no way of knowing which
  1261.        DIFF is in use.  */
  1262.     run_setup ("%s -c %s %s", DIFF, file1, file2);
  1263.  
  1264.     /* A retcode of 0 means no differences.  1 means some differences.  */
  1265.     if ((retcode = run_exec (RUN_TTY, file, RUN_TTY, RUN_NORMAL)) != 0
  1266.         && retcode != 1)
  1267.     {
  1268.         fail = 1;
  1269.     }
  1270.     else
  1271.     {
  1272. #define BINARY "Binary"
  1273.         char buf[sizeof BINARY];
  1274.         unsigned int c;
  1275.  
  1276.         /* Check the diff output to make sure patch will be handle it.  */
  1277.         e = fopen (file, "r");
  1278.         if (e == NULL)
  1279.         error (1, errno, "could not open diff output file %s", file);
  1280.         c = fread (buf, 1, sizeof BINARY - 1, e);
  1281.         buf[c] = '\0';
  1282.         if (strcmp (buf, BINARY) == 0)
  1283.         {
  1284.         /* These are binary files.  We could use diff -a, but
  1285.            patch can't handle that.  */
  1286.         fail = 1;
  1287.         }
  1288.         fclose (e);
  1289.     }
  1290.     }
  1291.  
  1292.     if (! fail)
  1293.     {
  1294.         Vers_TS *xvers_ts;
  1295.  
  1296.         /* This stuff is just copied blindly from checkout_file.  I
  1297.        don't really know what it does.  */
  1298.         xvers_ts = Version_TS (repository, options, tag, date, file,
  1299.                    force_tag_match, 0, entries, rcsnode);
  1300.     if (strcmp (xvers_ts->options, "-V4") == 0)
  1301.         xvers_ts->options[0] = '\0';
  1302.  
  1303.     Register (entries, file, xvers_ts->vn_rcs,
  1304.           xvers_ts->ts_user, xvers_ts->options,
  1305.           xvers_ts->tag, xvers_ts->date, NULL);
  1306.  
  1307.     if (stat (file2, file_info) < 0)
  1308.         error (1, errno, "could not stat %s", file2);
  1309.  
  1310.     /* If this is really Update and not Checkout, recode history */
  1311.     if (strcmp (command_name, "update") == 0)
  1312.         history_write ('P', update_dir, xvers_ts->vn_rcs, file,
  1313.                repository);
  1314.  
  1315.     freevers_ts (&xvers_ts);
  1316.  
  1317.     if (!really_quiet)
  1318.     {
  1319.         write_letter (file, 'P', update_dir);
  1320.     }
  1321.     }
  1322.     else
  1323.     {
  1324.     int old_errno = errno;        /* save errno value over the rename */
  1325.  
  1326.     if (isfile (backup))
  1327.         rename_file (backup, file);
  1328.  
  1329.     if (retcode != 0 && retcode != 1)
  1330.         error (retcode == -1 ? 1 : 0, retcode == -1 ? old_errno : 0,
  1331.            "could not diff %s", file);
  1332.  
  1333.     *docheckout = 1;
  1334.     retval = retcode;
  1335.     }
  1336.  
  1337.     (void) unlink_file (backup);
  1338.     (void) unlink_file (file1);
  1339.     (void) unlink_file (file2);
  1340.  
  1341.     return (retval);
  1342. }
  1343. #endif
  1344.  
  1345. /*
  1346.  * Several of the types we process only print a bit of information consisting
  1347.  * of a single letter and the name.
  1348.  */
  1349. static int
  1350. write_letter (file, letter, update_dir)
  1351.     char *file;
  1352.     int letter;
  1353.     char *update_dir;
  1354. {
  1355.     if (!really_quiet)
  1356.     {
  1357.     char buf[2];
  1358.     buf[0] = letter;
  1359.     buf[1] = ' ';
  1360.     cvs_output (buf, 2);
  1361.     if (update_dir[0])
  1362.     {
  1363.         cvs_output (update_dir, 0);
  1364.         cvs_output ("/", 1);
  1365.     }
  1366.     cvs_output (file, 0);
  1367.     cvs_output ("\n", 1);
  1368.     }
  1369.     return (0);
  1370. }
  1371.  
  1372. /*
  1373.  * Do all the magic associated with a file which needs to be merged
  1374.  */
  1375. static int
  1376. merge_file (file, repository, entries, vers, update_dir)
  1377.     char *file;
  1378.     char *repository;
  1379.     List *entries;
  1380.     Vers_TS *vers;
  1381.     char *update_dir;
  1382. {
  1383.     char user[PATH_MAX];
  1384.     char backup[PATH_MAX];
  1385.     int status;
  1386.     int retcode = 0;
  1387.  
  1388.     /*
  1389.      * The users currently modified file is moved to a backup file name
  1390.      * ".#filename.version", so that it will stay around for a few days
  1391.      * before being automatically removed by some cron daemon.  The "version"
  1392.      * is the version of the file that the user was most up-to-date with
  1393.      * before the merge.
  1394.      */
  1395.     (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user);
  1396.     if (update_dir[0])
  1397.     (void) sprintf (user, "%s/%s", update_dir, file);
  1398.     else
  1399.     (void) strcpy (user, file);
  1400.  
  1401.     (void) unlink_file (backup);
  1402.     copy_file (file, backup);
  1403.     xchmod (file, 1);
  1404.  
  1405.     status = RCS_merge(vers->srcfile->path, 
  1406.                vers->options, vers->vn_user, vers->vn_rcs);
  1407.     if (status != 0 && status != 1)
  1408.     {
  1409.     error (0, status == -1 ? errno : 0,
  1410.            "could not merge revision %s of %s", vers->vn_user, user);
  1411.     error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
  1412.            user, backup);
  1413.     rename_file (backup, file);
  1414.     return (1);
  1415.     }
  1416.  
  1417.     if (strcmp (vers->options, "-V4") == 0)
  1418.     vers->options[0] = '\0';
  1419.     (void) time (&last_register_time);
  1420.     {
  1421.     char *cp = 0;
  1422.  
  1423.     if (status)
  1424.         cp = time_stamp (file);
  1425.     Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options,
  1426.           vers->tag, vers->date, cp);
  1427.     if (cp)
  1428.         free (cp);
  1429.     }
  1430.  
  1431.     /* fix up the vers structure, in case it is used by join */
  1432.     if (join_rev1)
  1433.     {
  1434.     if (vers->vn_user != NULL)
  1435.         free (vers->vn_user);
  1436.     vers->vn_user = xstrdup (vers->vn_rcs);
  1437.     }
  1438.  
  1439. #ifdef SERVER_SUPPORT
  1440.     /* Send the new contents of the file before the message.  If we
  1441.        wanted to be totally correct, we would have the client write
  1442.        the message only after the file has safely been written.  */
  1443.     if (server_active)
  1444.     {
  1445.         server_copy_file (file, update_dir, repository, backup);
  1446.     server_updated (file, update_dir, repository, SERVER_MERGED,
  1447.             (struct stat *) NULL, (unsigned char *) NULL);
  1448.     }
  1449. #endif
  1450.  
  1451.     if (!noexec && !xcmp (backup, file))
  1452.     {
  1453.     printf ("%s already contains the differences between %s and %s\n",
  1454.         user, vers->vn_user, vers->vn_rcs);
  1455.     history_write ('G', update_dir, vers->vn_rcs, file, repository);
  1456.     return (0);
  1457.     }
  1458.  
  1459.     if (status == 1)
  1460.     {
  1461.     if (!noexec)
  1462.         error (0, 0, "conflicts found in %s", user);
  1463.  
  1464.     write_letter (file, 'C', update_dir);
  1465.  
  1466.     history_write ('C', update_dir, vers->vn_rcs, file, repository);
  1467.  
  1468.     }
  1469.     else if (retcode == -1)
  1470.     {
  1471.     error (1, errno, "fork failed while examining update of %s", user);
  1472.     }
  1473.     else
  1474.     {
  1475.     write_letter (file, 'M', update_dir);
  1476.     history_write ('G', update_dir, vers->vn_rcs, file, repository);
  1477.     }
  1478.     return (0);
  1479. }
  1480.  
  1481. /*
  1482.  * Do all the magic associated with a file which needs to be joined
  1483.  * (-j option)
  1484.  */
  1485. static void
  1486. #ifdef SERVER_SUPPORT
  1487. join_file (file, rcsnode, vers, update_dir, entries, repository)
  1488.     char *repository;
  1489. #else
  1490. join_file (file, rcsnode, vers, update_dir, entries)
  1491. #endif
  1492.     char *file;
  1493.     RCSNode *rcsnode;
  1494.     Vers_TS *vers;
  1495.     char *update_dir;
  1496.     List *entries;
  1497. {
  1498.     char user[PATH_MAX];
  1499.     char backup[PATH_MAX];
  1500.     char *options;
  1501.     int status;
  1502.  
  1503.     char *rev1;
  1504.     char *rev2;
  1505.     char *jrev1;
  1506.     char *jrev2;
  1507.     char *jdate1;
  1508.     char *jdate2;
  1509.  
  1510.     jrev1 = join_rev1;
  1511.     jrev2 = join_rev2;
  1512.     jdate1 = date_rev1;
  1513.     jdate2 = date_rev2;
  1514.  
  1515.     if (wrap_merge_is_copy (file))
  1516.     {
  1517.     /* FIXME: Should be including update_dir in message.  */
  1518.     error (0, 0,
  1519.            "Cannot merge %s because it is a merge-by-copy file.", file);
  1520.     return;
  1521.     }
  1522.  
  1523.     /* determine if we need to do anything at all */
  1524.     if (vers->srcfile == NULL ||
  1525.     vers->srcfile->path == NULL)
  1526.     {
  1527.     return;
  1528.     }
  1529.  
  1530.     /* in all cases, use two revs. */
  1531.  
  1532.     /* if only one rev is specified, it becomes the second rev */
  1533.     if (jrev2 == NULL)
  1534.     {
  1535.     jrev2 = jrev1;
  1536.     jrev1 = NULL;
  1537.     jdate2 = jdate1;
  1538.     jdate1 = NULL;
  1539.     }
  1540.  
  1541.     /* The file in the working directory doesn't exist in CVS/Entries.
  1542.        FIXME: Shouldn't this case result in additional processing (if
  1543.        the file was added going from rev1 to rev2, then do the equivalent
  1544.        of a "cvs add")?  (yes; easier said than done.. :-) */
  1545.     if (vers->vn_user == NULL)
  1546.     {
  1547.     /* No merge possible YET. */
  1548.     if (jdate2 != NULL)
  1549.         error (0, 0,
  1550.            "file %s is present in revision %s as of %s",
  1551.            file, jrev2, jdate2);
  1552.     else
  1553.         error (0, 0,
  1554.            "file %s is present in revision %s",
  1555.            file, jrev2);
  1556.     return;
  1557.     }
  1558.  
  1559.     /* Fix for bug CVS/193:
  1560.      * Used to dump core if the file had been removed on the current branch.
  1561.      */
  1562.     if (strcmp(vers->vn_user, "0") == 0)
  1563.     {
  1564.         error(0, 0,
  1565.               "file %s has been deleted",
  1566.               file);
  1567.         return;
  1568.     }
  1569.  
  1570.     /* convert the second rev spec, walking branches and dates. */
  1571.  
  1572.     rev2 = RCS_getversion (vers->srcfile, jrev2, jdate2, 1, 0);
  1573.     if (rev2 == NULL)
  1574.     {
  1575.     if (!quiet)
  1576.     {
  1577.         if (jdate2 != NULL)
  1578.         error (0, 0,
  1579.                "cannot find revision %s as of %s in file %s",
  1580.                jrev2, jdate2, file);
  1581.         else
  1582.         error (0, 0,
  1583.                "cannot find revision %s in file %s",
  1584.                jrev2, file);
  1585.     }
  1586.     return;
  1587.     }
  1588.  
  1589.     /* skip joining identical revs */
  1590.     if (strcmp (rev2, vers->vn_user) == 0)
  1591.     {
  1592.     /* No merge necessary.  */
  1593.     free (rev2);
  1594.     return;
  1595.     }
  1596.  
  1597.     if (jrev1 == NULL)
  1598.     {
  1599.     char *tst;
  1600.     /* if the first rev is missing, then it is implied to be the
  1601.        greatest common ancestor of both the join rev, and the
  1602.        checked out rev. */
  1603.     
  1604.     /* FIXME: What is this check for '!' about?  If it is legal to
  1605.        have '!' in the first character of vn_user, it isn't
  1606.        documented at struct vers_ts in cvs.h.  */
  1607.     tst = vers->vn_user;
  1608.     if (*tst == '!')
  1609.     {
  1610.         /* file was dead.  merge anyway and pretend it's been
  1611.            added. */
  1612.         ++tst;
  1613.         Register (entries, file, "0", vers->ts_user, vers->options,
  1614.               vers->tag, (char *) 0, (char *) 0);
  1615.     }
  1616.     rev1 = gca (tst, rev2);
  1617.     if (rev1 == NULL)
  1618.     {
  1619.         /* this should not be possible */
  1620.         error (0, 0, "bad gca");
  1621.         abort();
  1622.     }
  1623.  
  1624.     tst = RCS_gettag (vers->srcfile, rev2, 1, 0);
  1625.     if (tst == NULL)
  1626.     {
  1627.         /* this should not be possible. */
  1628.         error (0, 0, "cannot find gca");
  1629.         abort();
  1630.     }
  1631.  
  1632.     free (tst);
  1633.  
  1634.     /* these two cases are noops */
  1635.     if (strcmp (rev1, rev2) == 0)
  1636.     {
  1637.         free (rev1);
  1638.         free (rev2);
  1639.         return;
  1640.     }
  1641.     }
  1642.     else
  1643.     {
  1644.     /* otherwise, convert the first rev spec, walking branches and
  1645.        dates.  */
  1646.  
  1647.     rev1 = RCS_getversion (vers->srcfile, jrev1, jdate1, 1, 0);
  1648.     if (rev1 == NULL)
  1649.     {
  1650.       if (!quiet) {
  1651.         if (jdate1 != NULL)
  1652.         error (0, 0,
  1653.                "cannot find revision %s as of %s in file %s",
  1654.                jrev1, jdate1, file);
  1655.         else
  1656.         error (0, 0,
  1657.                "cannot find revision %s in file %s",
  1658.                jrev1, file);
  1659.       }
  1660.       return;
  1661.     }
  1662.     }
  1663.  
  1664.     /* do the join */
  1665.  
  1666. #if 0
  1667.     dome {
  1668.     /* special handling when two revisions are specified */
  1669.     if (join_rev1 && join_rev2)
  1670.     {
  1671.         rev = RCS_getversion (vers->srcfile, join_rev2, date_rev2, 1, 0);
  1672.         if (rev == NULL)
  1673.         {
  1674.         if (!quiet && date_rev2 == NULL)
  1675.             error (0, 0,
  1676.                "cannot find revision %s in file %s", join_rev2, file);
  1677.         return;
  1678.         }
  1679.         
  1680.         baserev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0);
  1681.         if (baserev == NULL)
  1682.         {
  1683.         if (!quiet && date_rev1 == NULL)
  1684.             error (0, 0,
  1685.                "cannot find revision %s in file %s", join_rev1, file);
  1686.         free (rev);
  1687.         return;
  1688.         }
  1689.         
  1690.         /*
  1691.          * nothing to do if:
  1692.          *    second revision matches our BASE revision (vn_user) &&
  1693.          *    both revisions are on the same branch
  1694.          */
  1695.         if (strcmp (vers->vn_user, rev) == 0 &&
  1696.         numdots (baserev) == numdots (rev))
  1697.         {
  1698.         /* might be the same branch.  take a real look */
  1699.         char *dot = strrchr (baserev, '.');
  1700.         int len = (dot - baserev) + 1;
  1701.         
  1702.         if (strncmp (baserev, rev, len) == 0)
  1703.             return;
  1704.         }
  1705.     }
  1706.     else
  1707.     {
  1708.         rev = RCS_getversion (vers->srcfile, join_rev1, date_rev1, 1, 0);
  1709.         if (rev == NULL)
  1710.         return;
  1711.         if (strcmp (rev, vers->vn_user) == 0) /* no merge necessary */
  1712.         {
  1713.         free (rev);
  1714.         return;
  1715.         }
  1716.         
  1717.         baserev = RCS_whatbranch (file, join_rev1, rcsnode);
  1718.         if (baserev)
  1719.         {
  1720.         char *cp;
  1721.         
  1722.         /* we get a branch -- turn it into a revision, or NULL if trunk */
  1723.         if ((cp = strrchr (baserev, '.')) == NULL)
  1724.         {
  1725.             free (baserev);
  1726.             baserev = (char *) NULL;
  1727.         }
  1728.         else
  1729.             *cp = '\0';
  1730.         }
  1731.     }
  1732.     if (baserev && strcmp (baserev, rev) == 0)
  1733.     {
  1734.         /* they match -> nothing to do */
  1735.         free (rev);
  1736.         free (baserev);
  1737.         return;
  1738.     }
  1739.     }
  1740. #endif
  1741.  
  1742.     /* OK, so we have two revisions; continue on */
  1743.  
  1744. #ifdef SERVER_SUPPORT
  1745.     if (server_active && !isreadable (file))
  1746.     {
  1747.     int retcode;
  1748.     /* The file is up to date.  Need to check out the current contents.  */
  1749.     retcode = RCS_checkout (vers->srcfile->path, "", vers->vn_user, NULL,
  1750.                             RUN_TTY, 0, 0);
  1751.     if (retcode != 0)
  1752.         error (1, retcode == -1 ? errno : 0,
  1753.            "failed to check out %s file", file);
  1754.     }
  1755. #endif
  1756.     
  1757.     /*
  1758.      * The users currently modified file is moved to a backup file name
  1759.      * ".#filename.version", so that it will stay around for a few days
  1760.      * before being automatically removed by some cron daemon.  The "version"
  1761.      * is the version of the file that the user was most up-to-date with
  1762.      * before the merge.
  1763.      */
  1764.     (void) sprintf (backup, "%s%s.%s", BAKPREFIX, file, vers->vn_user);
  1765.     if (update_dir[0])
  1766.     (void) sprintf (user, "%s/%s", update_dir, file);
  1767.     else
  1768.     (void) strcpy (user, file);
  1769.  
  1770.     (void) unlink_file (backup);
  1771.     copy_file (file, backup);
  1772.     xchmod (file, 1);
  1773.  
  1774.     options = vers->options;
  1775. #ifdef HAVE_RCS5
  1776. #if 0
  1777.     if (*options == '\0')
  1778.     options = "-kk";        /* to ignore keyword expansions */
  1779. #endif
  1780. #endif
  1781.  
  1782.     status = RCS_merge (vers->srcfile->path, options, rev1, rev2);
  1783.     if (status != 0 && status != 1)
  1784.     {
  1785.     error (0, status == -1 ? errno : 0,
  1786.            "could not merge revision %s of %s", rev2, user);
  1787.     error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
  1788.            user, backup);
  1789.     rename_file (backup, file);
  1790.     }
  1791.     free (rev1);
  1792.     free (rev2);
  1793.  
  1794. #ifdef SERVER_SUPPORT
  1795.     /*
  1796.      * If we're in server mode, then we need to re-register the file
  1797.      * even if there were no conflicts (status == 0).
  1798.      * This tells server_updated() to send the modified file back to
  1799.      * the client.
  1800.      */
  1801.     if (status == 1 || (status == 0 && server_active))
  1802. #else
  1803.     if (status == 1)
  1804. #endif
  1805.     {
  1806.     char *cp = 0;
  1807.  
  1808.     if (status)
  1809.         cp = time_stamp (file);
  1810.     Register (entries, file, vers->vn_rcs, vers->ts_rcs, vers->options,
  1811.           vers->tag, vers->date, cp);
  1812.     if (cp)
  1813.         free(cp);
  1814.     }
  1815.  
  1816. #ifdef SERVER_SUPPORT
  1817.     if (server_active)
  1818.     {
  1819.     server_copy_file (file, update_dir, repository, backup);
  1820.     server_updated (file, update_dir, repository, SERVER_MERGED,
  1821.             (struct stat *) NULL, (unsigned char *) NULL);
  1822.     }
  1823. #endif
  1824. }
  1825.  
  1826. int
  1827. joining ()
  1828. {
  1829.     return (join_rev1 != NULL);
  1830. }
  1831.